/*
@file: ast.h
@author: ZZH
@date: 2022-03-09
@info: 抽象语法树
*/
#pragma once
#include <QString>
#include <QList>
#include <cmath>
#include "calculator.h"
#include "libFun.h"

class ASTExpress_t
{
private:

protected:
    using BasicType = CalculatorConf::BasicType;

public:
    ASTExpress_t() {}
    virtual ~ASTExpress_t() {}

    virtual void calculate(BasicType* output) const = 0;
    virtual bool isDirty(void) const { return false; }
};

class ASTAdaptor_t:public ASTExpress_t
{
private:

protected:
    ASTExpress_t* child;
public:
    ASTAdaptor_t(ASTExpress_t* pChild):child(pChild) {}
    //adaptor在被析构时不释放子节点,因为它的作用就是自动断开释放链
    ~ASTAdaptor_t() {}

    virtual void calculate(BasicType* output) const override { this->child->calculate(output); }
    virtual bool isDirty(void) const override;
};

class ASTFunctionCall_t: public ASTExpress_t
{
private:

public:
    typedef void (*pf)(pFunCallArg_t pArgs, BasicType* output);

    typedef struct
    {
        pf pFunc;
        unsigned int numOfArg;
    } calFunc_t;

    // typedef void (*calFunc_t)(pFunCallArg_t pArgs, BasicType* output);

protected:
    pf Calcb;
    QList<ASTExpress_t*>* args;
public:
    ASTFunctionCall_t(pf fun, QList<ASTExpress_t*>* args):Calcb(fun), args(args) {}
    virtual ~ASTFunctionCall_t()
    {
        if (this->args)
        {
            for (auto exp : *args)
                delete exp;

            delete this->args;
        }
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        if (nullptr != this->args)
        {
            for (auto exp : *this->args)
            {
                if (exp->isDirty())
                    return true;
            }
        }

        return false;
    }
};

class ASTNumber_t:public ASTExpress_t
{
private:

protected:
    BasicType value;
public:
    ASTNumber_t(BasicType f):value(f) {}
    virtual ~ASTNumber_t() {}

    virtual void calculate(BasicType* output) const override
    {
        if (nullptr != output)
        {
            int allNum = Calculator_t::getInst().getTotolPoint();
            for (int i = 0;i < allNum;i++)
                output[i] = this->value;
        }
    }
};

class ASTDynamicNumber_t:public ASTExpress_t
{
private:

public:
    typedef enum
    {
        VariableT,
        VariableN,
        VariableFS,
        VariableI,
    }DynNumber_t;

protected:
    const DynNumber_t type;

public:
    ASTDynamicNumber_t(const DynNumber_t t):type(t) {}
    ~ASTDynamicNumber_t() {}

    virtual void calculate(BasicType* output) const override;
};

class ASTOperator_t:public ASTExpress_t
{
private:

protected:
    char op;//运算符
    ASTExpress_t* left, * right;//左子式和右子式

public:
    ASTOperator_t(char op, ASTExpress_t* l, ASTExpress_t* r):op(op), left(l), right(r) {}
    virtual ~ASTOperator_t()
    {
        if (nullptr != this->left)
            delete this->left;

        if (nullptr != this->right)
            delete this->right;
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        bool res = false;

        if (nullptr != this->left)
            res |= this->left->isDirty();

        if (nullptr != this->right)
            res |= this->right->isDirty();

        return res;
    }
};

class ASTCompare_t:public ASTExpress_t
{
public:
    typedef enum
    {
        EQU, // ==
        NEQU, // !=
        GEQU, // >=
        LEQU, //<=
        BAND, // &&
        BOR // ||
    }Compare_op_t;

protected:
    Compare_op_t op; //运算符
    ASTExpress_t* left, * right;//左子式和右子式

public:
    ASTCompare_t(Compare_op_t op, ASTExpress_t* l, ASTExpress_t* r):op(op), left(l), right(r) {}

    virtual ~ASTCompare_t()
    {
        if (nullptr != this->left)
            delete this->left;

        if (nullptr != this->right)
            delete this->right;
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        bool res = false;

        if (nullptr != this->left)
            res |= this->left->isDirty();

        if (nullptr != this->right)
            res |= this->right->isDirty();

        return res;
    }
};

class ASTCondition_t:public ASTExpress_t
{
private:

protected:
    ASTExpress_t* cond, * left, * right;
public:
    ASTCondition_t(ASTExpress_t* c, ASTExpress_t* l, ASTExpress_t* r):cond(c), left(l), right(r) {}
    ~ASTCondition_t()
    {
        if (nullptr != this->cond)
            delete this->cond;

        if (nullptr != this->left)
            delete this->left;

        if (nullptr != this->right)
            delete this->right;
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        bool res = false;

        if (nullptr != this->left)
            res |= this->left->isDirty();

        if (nullptr != this->right)
            res |= this->right->isDirty();

        if (nullptr != this->cond)
            res |= this->cond->isDirty();

        return res;
    }
};

class ASTString_t:public ASTExpress_t
{
private:
    const char* str;
protected:

public:
    ASTString_t(const char* s):str(s) {}
    ~ASTString_t()
    {
        if (nullptr != this->str)
            free((void*) this->str);
    }

    virtual void calculate(BasicType* output) const override
    {
        size_t* ptr = (size_t*) output;
        *ptr = (size_t) this->str;//指针传递
    }
};

class ASTList_t:public ASTExpress_t
{
private:

protected:
    QList<ASTExpress_t*>* members;
public:
    ASTList_t(QList<ASTExpress_t*>* list): members(list) {}

    ~ASTList_t()
    {
        if (nullptr != this->members)
        {
            for (auto pm : *members)
                delete pm;

            delete this->members;
        }
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        if (nullptr != this->members)
        {
            for (auto exp : *this->members)
            {
                if (exp->isDirty())
                    return true;
            }
        }

        return false;
    }
};
